//
// Copyright (c) 2006 Mikhail V. Denisenko.
// All rights reserved.
//
// Interface module for loading lwo files.
//

#include "stdafx.h"
#include "LwoParser.h"
#include <types.hpp>
#include <Polygon.h>
#include "ErnieWright\lwo2.h"


using std::auto_ptr;


enum LayerFlags
{
	Visible = 1,
};


enum PolygonType
{
	Face     = 'FACE',
	Curv     = 'CURV',
	Patch    = 'PTCH',
	Metaball = 'MBAL',
	Bone     = 'BONE',
};


enum VMapType
{
	Pick   = 'PICK',
	Weight = 'WGHT',
	Mnvw   = 'MNVW',
	TexUV  = 'TXUV',
	Rgb    = 'RGB ',
	Rgba   = 'RGBA',
	Morf   = 'MORF',
	Spot   = 'SPOT',
};


class LwObjectGuard
{
public:
	LwObjectGuard(lwObject* obj) : _obj(obj) {}
	~LwObjectGuard() { lwFreeObject(_obj); }

private:
	lwObject* _obj;
};


TexCoords FindTexCoord(lwPolVert* vert);
void LoadLayer(lwLayer * layer, ObjectBuilder * objBuilder);


LWOPARSER_API bool IsThisFromat(const char * const filename)
{
	return true;
}

LWOPARSER_API Object * LoadLwo(const char * const fileName)
{
	lwObject* obj = lwGetObject(fileName, 0, 0);
	LwObjectGuard guard(obj);

	ObjectBuilder objBuilder;

	// for each layer
	for (lwLayer* layer = obj->layer; layer; layer = layer->next)
	{
		// skip invisible layers
		if (!(layer->flags & Visible))
		{
			continue;
		}
		LoadLayer(layer, &objBuilder);
	}
	return objBuilder.Grab();
}

LWOPARSER_API Object * LoadLwo(const char * const fileName, int layerIndex)
{
	lwObject* obj = lwGetObject(fileName, 0, 0);
	LwObjectGuard guard(obj);

	ObjectBuilder objBuilder;

	// for each layer
	for (lwLayer* layer = obj->layer; layer; layer = layer->next)
	{
		// seeking requested layer
		if (layer->index != layerIndex)
		{
			continue;
		}
		LoadLayer(layer, &objBuilder);
	}
	return objBuilder.Grab();
}

TexCoords FindTexCoord(lwPolVert* vert)
{
	for (lwVMapPt* vmappt = vert->vm;
		vmappt != vert->vm + vert->nvmaps;
		vmappt++)
	{
		if (vmappt->vmap->type == TexUV)
		{
			return TexCoords(
				(*vmappt->vmap->val)[0],
				(*vmappt->vmap->val)[1]);
		}
	}
	return TexCoords(0, 0);
}


void LoadLayer(lwLayer * layer, ObjectBuilder * objBuilder)
{
	PolygonBuilder polyBuilder;

	// for each polygon in layer
	for (lwPolygon* pol = layer->polygon.pol;
		pol != layer->polygon.pol + layer->polygon.count;
		pol++)
	{
		// skip non face polygons
		if (pol->type != Face)
		{
			continue;
		}

		// begin polygon
		polyBuilder.Begin();
		for (lwPolVert* vert = pol->v;
			vert != pol->v + pol->nverts;
			vert++)
		{
			polyBuilder.AddPoint(
				layer->point.pt[vert->index].pos,
				vert->norm,
				FindTexCoord(vert));
		}
		objBuilder->AddPolygon(polyBuilder.Grab());
	}
}
